home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 7684 / 7684.xpi / resources / log4moz.js < prev   
Encoding:
Text File  |  2009-11-20  |  13.7 KB  |  535 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is log4moz
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  * Michael Johnston
  18.  * Portions created by the Initial Developer are Copyright (C) 2006
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  * Michael Johnston <special.michael@gmail.com>
  23.  * Dan Mills <thunder@mozilla.com>
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the MPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the MPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. const EXPORTED_SYMBOLS = ['Log4Moz'];
  40.  
  41. const Cc = Components.classes;
  42. const Ci = Components.interfaces;
  43. const Cr = Components.results;
  44. const Cu = Components.utils;
  45.  
  46. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  47.  
  48. const MODE_RDONLY   = 0x01;
  49. const MODE_WRONLY   = 0x02;
  50. const MODE_CREATE   = 0x08;
  51. const MODE_APPEND   = 0x10;
  52. const MODE_TRUNCATE = 0x20;
  53.  
  54. const PERMS_FILE      = 0644;
  55. const PERMS_DIRECTORY = 0755;
  56.  
  57. const ONE_BYTE = 1;
  58. const ONE_KILOBYTE = 1024 * ONE_BYTE;
  59. const ONE_MEGABYTE = 1024 * ONE_KILOBYTE;
  60.  
  61. let Log4Moz = {
  62.   Level: {
  63.     Fatal:  70,
  64.     Error:  60,
  65.     Warn:   50,
  66.     Info:   40,
  67.     Config: 30,
  68.     Debug:  20,
  69.     Trace:  10,
  70.     All:    0,
  71.     Desc: {
  72.       70: "FATAL",
  73.       60: "ERROR",
  74.       50: "WARN",
  75.       40: "INFO",
  76.       30: "CONFIG",
  77.       20: "DEBUG",
  78.       10: "TRACE",
  79.       0:  "ALL"
  80.     }
  81.   },
  82.  
  83.   get repository() {
  84.     delete Log4Moz.repository;
  85.     Log4Moz.repository = new LoggerRepository();
  86.     return Log4Moz.repository;
  87.   },
  88.   set repository(value) {
  89.     delete Log4Moz.repository;
  90.     Log4Moz.repository = value;
  91.   },
  92.  
  93.   get LogMessage() { return LogMessage; },
  94.   get Logger() { return Logger; },
  95.   get LoggerRepository() { return LoggerRepository; },
  96.  
  97.   get Formatter() { return Formatter; },
  98.   get BasicFormatter() { return BasicFormatter; },
  99.  
  100.   get Appender() { return Appender; },
  101.   get DumpAppender() { return DumpAppender; },
  102.   get ConsoleAppender() { return ConsoleAppender; },
  103.   get FileAppender() { return FileAppender; },
  104.   get RotatingFileAppender() { return RotatingFileAppender; },
  105.  
  106.   // Logging helper:
  107.   // let logger = Log4Moz.repository.getLogger("foo");
  108.   // logger.info(Log4Moz.enumerateInterfaces(someObject).join(","));
  109.   enumerateInterfaces: function Log4Moz_enumerateInterfaces(aObject) {
  110.     let interfaces = [];
  111.  
  112.     for (i in Ci) {
  113.       try {
  114.         aObject.QueryInterface(Ci[i]);
  115.         interfaces.push(i);
  116.       }
  117.       catch(ex) {}
  118.     }
  119.  
  120.     return interfaces;
  121.   },
  122.  
  123.   // Logging helper:
  124.   // let logger = Log4Moz.repository.getLogger("foo");
  125.   // logger.info(Log4Moz.enumerateProperties(someObject).join(","));
  126.   enumerateProperties: function Log4Moz_enumerateProps(aObject,
  127.                                                        aExcludeComplexTypes) {
  128.     let properties = [];
  129.  
  130.     for (p in aObject) {
  131.       try {
  132.         if (aExcludeComplexTypes &&
  133.             (typeof aObject[p] == "object" || typeof aObject[p] == "function"))
  134.           continue;
  135.         properties.push(p + " = " + aObject[p]);
  136.       }
  137.       catch(ex) {
  138.         properties.push(p + " = " + ex);
  139.       }
  140.     }
  141.  
  142.     return properties;
  143.   }
  144. };
  145.  
  146.  
  147. /*
  148.  * LogMessage
  149.  * Encapsulates a single log event's data
  150.  */
  151. function LogMessage(loggerName, level, message){
  152.   this.loggerName = loggerName;
  153.   this.message = message;
  154.   this.level = level;
  155.   this.time = Date.now();
  156. }
  157. LogMessage.prototype = {
  158.   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
  159.  
  160.   get levelDesc() {
  161.     if (this.level in Log4Moz.Level.Desc)
  162.       return Log4Moz.Level.Desc[this.level];
  163.     return "UNKNOWN";
  164.   },
  165.  
  166.   toString: function LogMsg_toString(){
  167.     return "LogMessage [" + this.time + " " + this.level + " " +
  168.       this.message + "]";
  169.   }
  170. };
  171.  
  172. /*
  173.  * Logger
  174.  * Hierarchical version.  Logs to all appenders, assigned or inherited
  175.  */
  176.  
  177. function Logger(name, repository) {
  178.   this._init(name, repository);
  179. }
  180. Logger.prototype = {
  181.   _init: function Logger__init(name, repository) {
  182.     if (!repository)
  183.       repository = Log4Moz.repository;
  184.     this._name = name;
  185.     this._appenders = [];
  186.     this._repository = repository;
  187.   },
  188.  
  189.   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
  190.  
  191.   parent: null,
  192.  
  193.   get name() {
  194.     return this._name;
  195.   },
  196.  
  197.   _level: null,
  198.   get level() {
  199.     if (this._level != null)
  200.       return this._level;
  201.     if (this.parent)
  202.       return this.parent.level;
  203.     dump("log4moz warning: root logger configuration error: no level defined\n");
  204.     return Log4Moz.Level.All;
  205.   },
  206.   set level(level) {
  207.     this._level = level;
  208.   },
  209.  
  210.   _appenders: null,
  211.   get appenders() {
  212.     if (!this.parent)
  213.       return this._appenders;
  214.     return this._appenders.concat(this.parent.appenders);
  215.   },
  216.  
  217.   addAppender: function Logger_addAppender(appender) {
  218.     for (let i = 0; i < this._appenders.length; i++) {
  219.       if (this._appenders[i] == appender)
  220.         return;
  221.     }
  222.     this._appenders.push(appender);
  223.   },
  224.  
  225.   log: function Logger_log(message) {
  226.     if (this.level > message.level)
  227.       return;
  228.     let appenders = this.appenders;
  229.     for (let i = 0; i < appenders.length; i++){
  230.       appenders[i].append(message);
  231.     }
  232.   },
  233.  
  234.   fatal: function Logger_fatal(string) {
  235.     this.log(new LogMessage(this._name, Log4Moz.Level.Fatal, string));
  236.   },
  237.   error: function Logger_error(string) {
  238.     this.log(new LogMessage(this._name, Log4Moz.Level.Error, string));
  239.   },
  240.   warn: function Logger_warn(string) {
  241.     this.log(new LogMessage(this._name, Log4Moz.Level.Warn, string));
  242.   },
  243.   info: function Logger_info(string) {
  244.     this.log(new LogMessage(this._name, Log4Moz.Level.Info, string));
  245.   },
  246.   config: function Logger_config(string) {
  247.     this.log(new LogMessage(this._name, Log4Moz.Level.Config, string));
  248.   },
  249.   debug: function Logger_debug(string) {
  250.     this.log(new LogMessage(this._name, Log4Moz.Level.Debug, string));
  251.   },
  252.   trace: function Logger_trace(string) {
  253.     this.log(new LogMessage(this._name, Log4Moz.Level.Trace, string));
  254.   }
  255. };
  256.  
  257. /*
  258.  * LoggerRepository
  259.  * Implements a hierarchy of Loggers
  260.  */
  261.  
  262. function LoggerRepository() {}
  263. LoggerRepository.prototype = {
  264.   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
  265.  
  266.   _loggers: {},
  267.  
  268.   _rootLogger: null,
  269.   get rootLogger() {
  270.     if (!this._rootLogger) {
  271.       this._rootLogger = new Logger("root", this);
  272.       this._rootLogger.level = Log4Moz.Level.All;
  273.     }
  274.     return this._rootLogger;
  275.   },
  276.   // FIXME: need to update all parent values if we do this
  277.   //set rootLogger(logger) {
  278.   //  this._rootLogger = logger;
  279.   //},
  280.  
  281.   _updateParents: function LogRep__updateParents(name) {
  282.     let pieces = name.split('.');
  283.     let cur, parent;
  284.  
  285.     // find the closest parent
  286.     // don't test for the logger name itself, as there's a chance it's already
  287.     // there in this._loggers
  288.     for (let i = 0; i < pieces.length - 1; i++) {
  289.       if (cur)
  290.         cur += '.' + pieces[i];
  291.       else
  292.         cur = pieces[i];
  293.       if (cur in this._loggers)
  294.         parent = cur;
  295.     }
  296.  
  297.     // if we didn't assign a parent above, there is no parent
  298.     if (!parent)
  299.       this._loggers[name].parent = this.rootLogger;
  300.     else
  301.       this._loggers[name].parent = this._loggers[parent];
  302.  
  303.     // trigger updates for any possible descendants of this logger
  304.     for (let logger in this._loggers) {
  305.       if (logger != name && logger.indexOf(name) == 0)
  306.         this._updateParents(logger);
  307.     }
  308.   },
  309.  
  310.   getLogger: function LogRep_getLogger(name) {
  311.     if (!name)
  312.       name = this.getLogger.caller.name;
  313.     if (name in this._loggers)
  314.       return this._loggers[name];
  315.     this._loggers[name] = new Logger(name, this);
  316.     this._updateParents(name);
  317.     return this._loggers[name];
  318.   }
  319. };
  320.  
  321. /*
  322.  * Formatters
  323.  * These massage a LogMessage into whatever output is desired
  324.  * Only the BasicFormatter is currently implemented
  325.  */
  326.  
  327. // Abstract formatter
  328. function Formatter() {}
  329. Formatter.prototype = {
  330.   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
  331.   format: function Formatter_format(message) {}
  332. };
  333.  
  334. // FIXME: should allow for formatting the whole string, not just the date
  335. function BasicFormatter(dateFormat) {
  336.   if (dateFormat)
  337.     this.dateFormat = dateFormat;
  338. }
  339. BasicFormatter.prototype = {
  340.   __proto__: Formatter.prototype,
  341.  
  342.   _dateFormat: null,
  343.  
  344.   get dateFormat() {
  345.     if (!this._dateFormat)
  346.       this._dateFormat = "%Y-%m-%d %H:%M:%S";
  347.     return this._dateFormat;
  348.   },
  349.  
  350.   set dateFormat(format) {
  351.     this._dateFormat = format;
  352.   },
  353.  
  354.   format: function BF_format(message) {
  355.     let date = new Date(message.time);
  356.     return date.toLocaleFormat(this.dateFormat) + "\t" +
  357.       message.loggerName + "\t" + message.levelDesc + "\t" +
  358.       message.message + "\n";
  359.   }
  360. };
  361.  
  362. /*
  363.  * Appenders
  364.  * These can be attached to Loggers to log to different places
  365.  * Simply subclass and override doAppend to implement a new one
  366.  */
  367.  
  368. function Appender(formatter) {
  369.   this._name = "Appender";
  370.   this._formatter = formatter? formatter : new BasicFormatter();
  371. }
  372. Appender.prototype = {
  373.   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
  374.  
  375.   _level: Log4Moz.Level.All,
  376.   get level() { return this._level; },
  377.   set level(level) { this._level = level; },
  378.  
  379.   append: function App_append(message) {
  380.     if(this._level <= message.level)
  381.       this.doAppend(this._formatter.format(message));
  382.   },
  383.   toString: function App_toString() {
  384.     return this._name + " [level=" + this._level +
  385.       ", formatter=" + this._formatter + "]";
  386.   },
  387.   doAppend: function App_doAppend(message) {}
  388. };
  389.  
  390. /*
  391.  * DumpAppender
  392.  * Logs to standard out
  393.  */
  394.  
  395. function DumpAppender(formatter) {
  396.   this._name = "DumpAppender";
  397.   this._formatter = formatter? formatter : new BasicFormatter();
  398. }
  399. DumpAppender.prototype = {
  400.   __proto__: Appender.prototype,
  401.  
  402.   doAppend: function DApp_doAppend(message) {
  403.     dump(message);
  404.   }
  405. };
  406.  
  407. /*
  408.  * ConsoleAppender
  409.  * Logs to the javascript console
  410.  */
  411.  
  412. function ConsoleAppender(formatter) {
  413.   this._name = "ConsoleAppender";
  414.   this._formatter = formatter;
  415. }
  416. ConsoleAppender.prototype = {
  417.   __proto__: Appender.prototype,
  418.  
  419.   doAppend: function CApp_doAppend(message) {
  420.     if (message.level > Log4Moz.Level.Warn) {
  421.       Cu.reportError(message);
  422.       return;
  423.     }
  424.     Cc["@mozilla.org/consoleservice;1"].
  425.       getService(Ci.nsIConsoleService).logStringMessage(message);
  426.   }
  427. };
  428.  
  429. /*
  430.  * FileAppender
  431.  * Logs to a file
  432.  */
  433.  
  434. function FileAppender(file, formatter) {
  435.   this._name = "FileAppender";
  436.   this._file = file; // nsIFile
  437.   this._formatter = formatter? formatter : new BasicFormatter();
  438. }
  439. FileAppender.prototype = {
  440.   __proto__: Appender.prototype,
  441.  
  442.   __fos: null,
  443.   get _fos() {
  444.     if (!this.__fos)
  445.       this.openStream();
  446.     return this.__fos;
  447.   },
  448.  
  449.   openStream: function FApp_openStream() {
  450.     this.__fos = Cc["@mozilla.org/network/file-output-stream;1"].
  451.       createInstance(Ci.nsIFileOutputStream);
  452.     let flags = MODE_WRONLY | MODE_CREATE | MODE_APPEND;
  453.     this.__fos.init(this._file, flags, PERMS_FILE, 0);
  454.   },
  455.  
  456.   closeStream: function FApp_closeStream() {
  457.     if (!this.__fos)
  458.       return;
  459.     try {
  460.       this.__fos.close();
  461.       this.__fos = null;
  462.     } catch(e) {
  463.       dump("Failed to close file output stream\n" + e);
  464.     }
  465.   },
  466.  
  467.   doAppend: function FApp_doAppend(message) {
  468.     if (message === null || message.length <= 0)
  469.       return;
  470.     try {
  471.       this._fos().write(message, message.length);
  472.     } catch(e) {
  473.       dump("Error writing file:\n" + e);
  474.     }
  475.   },
  476.  
  477.   clear: function FApp_clear() {
  478.     this.closeStream();
  479.     this._file.remove(false);
  480.   }
  481. };
  482.  
  483. /*
  484.  * RotatingFileAppender
  485.  * Similar to FileAppender, but rotates logs when they become too large
  486.  */
  487.  
  488. function RotatingFileAppender(file, formatter, maxSize, maxBackups) {
  489.   if (maxSize === undefined)
  490.     maxSize = ONE_MEGABYTE * 2;
  491.  
  492.   if (maxBackups === undefined)
  493.     maxBackups = 0;
  494.  
  495.   this._name = "RotatingFileAppender";
  496.   this._file = file; // nsIFile
  497.   this._formatter = formatter? formatter : new BasicFormatter();
  498.   this._maxSize = maxSize;
  499.   this._maxBackups = maxBackups;
  500. }
  501. RotatingFileAppender.prototype = {
  502.   __proto__: FileAppender.prototype,
  503.  
  504.   doAppend: function RFApp_doAppend(message) {
  505.     if (message === null || message.length <= 0)
  506.       return;
  507.     try {
  508.       this.rotateLogs();
  509.       this._fos.write(message, message.length);
  510.     } catch(e) {
  511.       dump("Error writing file:\n" + e);
  512.     }
  513.   },
  514.   rotateLogs: function RFApp_rotateLogs() {
  515.     if(this._file.exists() &&
  516.        this._file.fileSize < this._maxSize)
  517.       return;
  518.  
  519.     this.closeStream();
  520.  
  521.     for (let i = this.maxBackups - 1; i > 0; i--){
  522.       let backup = this._file.parent.clone();
  523.       backup.append(this._file.leafName + "." + i);
  524.       if (backup.exists())
  525.         backup.moveTo(this._file.parent, this._file.leafName + "." + (i + 1));
  526.     }
  527.  
  528.     let cur = this._file.clone();
  529.     if (cur.exists())
  530.       cur.moveTo(cur.parent, cur.leafName + ".1");
  531.  
  532.     // Note: this._file still points to the same file
  533.   }
  534. };
  535.